01 - Core/06 - Refs.js (78 lines of code) (raw):

// This is a refs proposal that uses callbacks instead of strings. The callback // can be easily statically typed and solves most use cases. // When a ref is attached, it gets passed the instance as the first argument. // When a ref is detached, the callback is invoked with null as the argument. // refs on DOM nodes gives the DOM node handle directly, not an intermediate // form. class Foo { myDivRef : ?HTMLDivElement; handleTick() { this.setState({ width: this.myDivRef.offsetWidth }); } render() { return ( <C tick={this.handleTick}> <div ref={node => this.myDivRef = node} /> <CustomComponent context={() => this.myDivRef} /> </C> ); } } // It's possible to distinguish whether a ref as ever been mounted or if it has // been mounted during this particular reconciliation phase. class Component { buttonWasEverMounted : boolean; buttonWasMountedThisPass : boolean; button : ?Button; mountButtonRef = button => { if (button) { this.buttonWasEverMounted = true; this.buttonWasMountedThisPass = true; } this.button = button; } componentWillMount() { this.componentWillUpdate(); } componentDidMount() { this.componentDidUpdate(); } componentWillUpdate() { this.buttonWasMountedThisPass = false; } componentDidUpdate() { if (this.buttonWasEverMounted) { console.log('button was mounted at least once'); } if (this.buttonWasMountedThisPass) { console.log('button was mounted during this render pass'); } } render() { return <Button ref={this.mountButtonRef} />; } } // In a future world where every callback is also implemented as an Observer, // we can pass a subject to the ref to build Observable compositions on top // of a ref. class Foo { myTick = new Rx.Subject(); myDiv = new Rx.Subject(); observe() { var widths = this.myDiv.map(myDivRef => myDivRef.offsetWidth); return { width: this.myTick.combineLatest(widths, (e, width) => width) }; } render() { return ( <C tick={this.myTick}> <div ref={this.myDiv} /> <CustomComponent context={this.myDiv} /> </C> ); } } // Getting your "own" DOM node is still possible with a call to traverse the // composites until you get to the DOM node. class Foo { handleTick() { var node = React.findDOMNode(this); this.setState({ width: node.offsetWidth }); } render() { return ( <C tick={this.handleTick}> <div /> </C> ); } }